iOS 内存优化之-序章·启动时间内存优化

#一.序章·检测启动时间

1.1.配置环境

DYLD_PRINT_STATISTICS

1.2.main函数

1
2
3
4
5
6
7
8
9
10
11
#import <UIKit/UIKit.h>
#import "AppDelegate.h"

CFAbsoluteTime startTime;

int main(int argc, char * argv[]) {
@autoreleasepool {
startTime = CFAbsoluteTimeGetCurrent();
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

1.3.appdelegate

1
2
3
4
5
6
7
8

@implementation AppDelegate
extern CFAbsoluteTime startTime;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(@"launch Time = %f 秒",(CFAbsoluteTimeGetCurrent() - startTime));
// Override point for customization after application launch.
return YES;
}

##二.序章·启动时间到底怎么算

  • t(App总启动时间) = t1(main()之前的加载时间) + t2(main()之后的加载时间)。

  • t1 = 系统dylib(动态链接库)和自身App可执行文件的加载;

    main()调用之前的加载过程

    App开始启动后, 系统首先加载可执行文件(自身App的所有.o文件的集合),然后加载动态链接库dyld,dyld是一个专门用来加载动态链接库的库。 执行从dyld开始,dyld从可执行文件的依赖开始, 递归加载所有的依赖动态链接库。 
动态链接库包括:iOS 中用到的所有系统 framework,加载OC runtime方法的libobjc,系统级别的libSystem,例如libdispatch(GCD)libsystem_blocks (Block)

  • t2 = main方法执行之后到AppDelegate类中的- (BOOL)Application:(UIApplication *)Application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法执行结束前这段时间,主要是构建第一个界面,并完成渲染展示。

三.序章·App 首页测试以及优化方案

3.1.测试

一次测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2018-03-16 09:43:10.677774+0800 DianJingNet[41750:25192568] ====================t1
2018-03-16 09:43:10.731820+0800 DianJingNet[41750:25192568] ====================t2

2018-03-16 09:43:10.734283+0800 DianJingNet[41750:25192568] ====================语音合成初始化开始
2018-03-16 09:43:10.925331+0800 DianJingNet[41750:25192568] ====================语音合成初始化结束

2018-03-16 09:43:10.925380+0800 DianJingNet[41750:25192568] ====================科大讯飞初始化开始
2018-03-16 09:43:11.762784+0800 DianJingNet[41750:25192568] ====================科大讯飞初始化结束

2018-03-16 09:43:11.762845+0800 DianJingNet[41750:25192568] ====================百度统计初始化开始
2018-03-16 09:43:11.776646+0800 DianJingNet[41750:25192568] ====================百度统计初始化结束

2018-03-16 09:43:11.779596+0800 DianJingNet[41750:25192568] ====================通知等配置初始化开始
2018-03-16 09:43:13.330401+0800 DianJingNet[41750:25192568] ====================通知等配置初始化结束

2018-03-16 09:43:13.330663+0800 DianJingNet[41750:25192568] ====================t3

二次测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1521184270.643068 ====================t1
1521184270.710496 ====================t2
1521184270.711700 ====================语音合成初始化开始
1521184271.586019 ====================语音合成初始化结束
1521184271.586087 ====================科大讯飞初始化开始
1521184272.257549 ====================科大讯飞初始化结束
1521184272.257846 ====================百度统计初始化开始
1521184272.283830 ====================百度统计初始化结束
1521184272.287952 ====================通知等配置初始化开始
1521184272.413938 ====================判断1
1521184272.414801 ====================判断1结束
1521184272.415319 ====================判断2结束
1521184272.464177 ====================判断3.1结束
1521184272.474976 ====================通知等配置初始化结束
1521184272.475151 ====================t3

3.2测试结果

测试情况 机型 7plus

一次测试加载时间一共 2.65s

二次测试加载时间一共 1.83 s

3.3.正常情况

  • app 热启动时间(不加载t1的时间包括动态链接库和可执行.o 文件的)

    1次记录 5.37

    1次记录 5.38

    1次记录 5.28

    1次记录 4.94

    1次记录 5.12

    1次记录 4.84

    1次记录 5.1

  • 冷启动时间 5.2

3.4.定位各个位置启动时间

  • 去除 didFinishLaunchingWithOptions无关代码后使用 textController的加载时间

    热启动 闪进 0.22s 左右

    冷启动 闪进 0.22s 左右
  • 正常添加 rootController 后的加载时间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1521169741.932117 ====================t1
1521169741.980573 ====================t2
1521169741.981245 ====================root开始
1521169743.999526 ====================root结束
1521169744.007790 ====================t3
···
didFinishLaunchingWithOptions 2.07s 左右
didFinishLaunchingWithOptions 2.07s 左右

测试结果

热启动
1次记录 4.35
1次记录 4.1
1次记录 4.2
1次记录 4.1
1次记录 4.1

冷启动
4.2
热启动
Root 前台页面LJMerchineServiceHomeController
1次记录 1.5
1次记录 1.4
1次记录 1.6
1次记录 1.6
  • 加载启动时所有sdk初始化 rootcontroller 设置为 text 控制器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1521172348.233823 ====================t1
1521172348.397602 ====================t2
1521172348.405184 ====================语音合成初始化开始
1521172351.358780 ====================语音合成初始化结束
1521172351.358856 ====================科大讯飞初始化开始
1521172352.182833 ====================科大讯飞初始化结束
1521172352.182864 ====================百度统计初始化开始
1521172352.227186 ====================百度统计初始化结束
1521172352.229374 ====================通知等配置初始化开始
1521172352.395328 ====================t3

冷启动总共4.16s + 1= 5.16s
热启动
1次记录1.04
1次记录1.2
1次记录1.06
1次记录1.16
  • 耗时合计

    冷启动 :各种sdk初始化 2.65s
    rootController初始化 2.07s<br>
    

四.序章·定位位置以及优化方案

  • 纯代码方式而不是storyboard加载首页UI。
  • 对didFinishLaunching里的函数考虑能否挖掘可以延迟加载或者懒加载,需要与各个业务方pm和rd共同check 对于一些已经下线的业务,删减冗余代码。 
对于一些与UI展示无关的业务,如微博认证过期检查、图片最大缓存空间设置等做延迟加载
  • 对实现了+load()方法的类进行分析,尽量将load里的代码延后调用。
  • 上面统计数据显示展示feed的导航控制器页面(NewsListViewController)比较耗时,对于viewDidLoad以及viewWillAppear方法中尽量去尝试少做,晚做,不做。
  • 每次用NSLog方式打印会隐式的创建一个Calendar,因此需要删减启动时各业务方打的log,或者仅仅针对内测版输出log
  • 加载大量图片imagewithnames 占用内存,imagewithcontentfile 不会